package io.github.wslxm.springbootplus2.file.util;


import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.IdUtil;
import io.github.wslxm.springbootplus2.core.config.error.ErrorException;
import io.github.wslxm.springbootplus2.core.result.ResultType;
import io.github.wslxm.springbootplus2.core.utils.date.XjLocalDateTimeUtil;
import io.github.wslxm.springbootplus2.file.constant.RenameRuleEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 * 上文件上传格式验证器，及文件后缀名 统一处理工具类
 * @author wangsong
 * @date 2020/12/11 0011 14:01
 * @return
 * @version 1.0.1
 */
@SuppressWarnings("all")
@Slf4j
public class FileUploadUtil {

    /**
     * 非法文件后缀
     */
    private static List<String> excludeFileSuffix;     // 任意禁止上传的文件格式

    static {
        excludeFileSuffix = Arrays.asList(("jsp,js,java,sh,bat").split(","));
    }


    /**
     * 上传路径文件格式判断
     *
     * @param fileName 当前上传的文件名称
     * @param filenameRule 保存后的文件名规则
     * @return fileName
     */
    public static String getNewFileName(String fileName, String filenameRule) {
        // 验证是否非法文件
        fileVerification(excludeFileSuffix, fileName);
        // 文件名特殊符号处理
        fileName = fileNameHandle(fileName);
        // 通过规则获取新的文件名
        return getNewFileNameByRule(fileName, filenameRule);
    }

    /**
     * 获取上传存储路径
     *
     * @param request 当前请求对象
     * @param applicationName 当前服务名称, 为 null 时将不拼接服务名称
     * @return fileName
     */
    public static String getFilePath(HttpServletRequest request, String applicationName) {
        // 时间
        String timeName = XjLocalDateTimeUtil.parse(LocalDateTime.now(), "yyyyMMdd");
        // 来源的最后一级
        String referer = request.getHeader("referer");
        String refererName = null;
        if (referer != null) {
            referer = referer.split("\\?")[0];
            String[] refererArray = referer.split("/");
            refererName = refererArray[refererArray.length - 1];
        }
        if (StringUtils.isNotBlank(applicationName) && StringUtils.isNotBlank(refererName)) {
            return applicationName + "/" + timeName + "/" + refererName;
        } else if (StringUtils.isNotBlank(applicationName)) {
            return applicationName + "/" + timeName;
        } else if (StringUtils.isNotBlank(refererName)) {
            return timeName + "/" + refererName;
        } else {
            return timeName;
        }
    }


    /**
     * 验证是否是非法文件
     *
     * suffixs    排除集(判断是否存在当前值)
     * suffixName 当前值
     */
    private static void fileVerification(List<String> excludeFileSuffix, String fileName) {
        // 验证格式是否禁止上传
        String suffixName = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).toLowerCase();
        if (excludeFileSuffix != null && excludeFileSuffix.contains(suffixName)) {
            throw new ErrorException(ResultType.FILE_DISABLE_FORMAT);
        }
    }


    /**
     * 获取新的文件名
     *
     * @param fileName 文件名称
     * @param filenameRule 新的文件名文件名获取规则
     * @return {@link String}
     */
    private static String getNewFileNameByRule(String fileName, String filenameRule) {
        // 生成上传后的文件名前缀
        String prefix = "";
        if (RenameRuleEnum.NO.getValue().equals(filenameRule)) {
            prefix = "";
        } else if (RenameRuleEnum.TIME.getValue().equals(filenameRule)) {
            prefix = getTimeStr12() + "-";
        } else if (RenameRuleEnum.UUID.getValue().equals(filenameRule)) {
            prefix = IdUtil.simpleUUID() + "-";
        } else if (RenameRuleEnum.SNOWFLAKE.getValue().equals(filenameRule)) {
            prefix = IdUtil.getSnowflakeNextIdStr() + "-";
        }
        return prefix + fileName;
    }


    /**
     * 获取随机串（时间-- 2位秒+3位毫秒+3位随机数 = 8位随机串）
     *
     * @return
     */
    private static String getTimeStr8() {
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            log.error(e.toString());
        }
        String timeStamp = new SimpleDateFormat("ssSSS").format(new Date());
        Random random = new Random();
        for (int i = 0; i < 3; i++) {
            timeStamp += (random.nextInt(10) + "");
        }
        return timeStamp;
    }

    /**
     * // 原 获取随机串（时间-- 2位秒+3位毫秒+3位随机数 = 8位随机串）
     * 新 获取随机串（时间-- 8位年月日 +3位时间戳= 1位随机数 = 12位可以区分日期的随机串）
     *
     * @return
     */
    private static String getTimeStr12() {
        String timeStamp = new SimpleDateFormat("yyyyMMdd-SSS").format(new Date());
        Random random = new Random();
        for (int i = 0; i < 1; i++) {
            timeStamp += (random.nextInt(10) + "");
        }
        ThreadUtil.sleep(1);
        return timeStamp;
    }


    /**
     * 获取图片大小
     */
    private static Integer getImgSize(InputStream inputStream) {
        int count = 0;
        try {
            while (count == 0) {
                count = inputStream.available();
            }
        } catch (IOException e) {
            log.error(e.toString());
        }
        return count;
    }

    /**
     * 文件名处理
     *
     * @param fileName 文件名称
     * @return {@link String}
     */
    private static String fileNameHandle(String fileName) {
        // 文件名中对url中不安全的字符处理
        return fileName.replaceAll("\\+", "")
                .replaceAll(":", "")
                .replaceAll("：", "")
                .replaceAll("（", "")
                .replaceAll("）", "")
                .replaceAll("\\(", "")
                .replaceAll("\\)", "")
                .replaceAll(" ", "")
                .replaceAll("/", "")
                .replaceAll("\\?", "")
                .replaceAll("%", "")
                .replaceAll("#", "")
                .replaceAll("&", "")
                .replaceAll("=", "");
    }
}
